// 1.10 获取XSTS(Xbox Secure Token Service)令牌（doXstsAuthorization）
// 获取webToken和streamingToken
use serde::{Serialize, Deserialize};
use reqwest::Client;
use crate::db::{db_select::db_select, db_insert::db_insert};
use crate::api::get_signature::get_signature;
use crate::api::{get_sisu_token::{get_sisu_device_token, get_sisu_user_token, get_title_token}};
use anyhow::{Result,anyhow};
use serde_json;
use chrono::{DateTime, Utc};
use std::str::FromStr;

/* 发送json结构体 */
#[derive(Debug, Serialize, Deserialize)]
struct payload{
    Properties: Properties,
    RelyingParty: String,
    TokenType: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct Properties{
    SandboxId: String,
    DeviceToken: String,
    TitleToken: String,
    UserTokens: Vec<String>,
}
/* 接收json结构体 */
#[derive(Debug, Serialize, Deserialize)]
struct response{
    IssueInstant: String,
    NotAfter: String,
    Token: String,
    DisplayClaims: DisplayClaims,
}

#[derive(Debug, Serialize, Deserialize)]
struct DisplayClaims {
    xui: Vec<XuiClaim>          // 注意：JSON中是数组
}

#[derive(Debug, Serialize, Deserialize)]
struct XuiClaim {
    uhs: String                 // 用户句柄标识
}

pub struct xsts_web_token{
    pub web_token:String,
    pub uhs:String,
}

/* 网络获取token */
pub async fn get_xsts_web_token() -> Result<xsts_web_token> {

    {
        // 检查数据库中的xsts_web_token是否存在且未过期
        if let Ok(config) = db_select("xsts_web_token_not_after").await {
            let expiry:DateTime<Utc> = DateTime::from_str(&config.value).expect("invalid datetime format");
            let now = Utc::now();
            if(now < expiry){
                // 没过期，直接返回
                return Ok(
                    xsts_web_token{
                        web_token: db_select("xsts_web_token").await.unwrap().value,
                        uhs: db_select("xsts_web_token_uhs").await.unwrap().value,
                    }
                );
            }
        }
    }
    let title_token = get_title_token().await.unwrap();
    let client = Client::new();
    let body = payload{
        Properties: Properties{
            SandboxId: "RETAIL".to_string(),
            DeviceToken: get_sisu_device_token().await.unwrap(),
            TitleToken: title_token,
            UserTokens: vec![get_sisu_user_token().await.unwrap()],
        },
        RelyingParty: "http://xboxlive.com".to_string(),
        TokenType: "JWT".to_string(),
    };

    let body = serde_json::to_string(&body).unwrap();
    println!("XSTS Request Body: {}", body);
    
    // let auth_token = get_sisu_token().await.unwrap();
    let signature = get_signature("https://xsts.auth.xboxlive.com/xsts/authorize", "", &body);

    println!("XSTS Signature: {}", signature);
    let response = client.post("https://xsts.auth.xboxlive.com/xsts/authorize")
        .header("x-xbl-contract-version", "1")
        .header("Cache-Control", "no-store, must-revalidate, no-cache")
        .header("Signature", signature)
        // .header("Content-Type", "application/json")
        .body(body)
        .send().await.unwrap();
    let response_code = response.status().as_u16();
    let response_text = response.text().await.unwrap();

    match response_code {
        200 => {
            let token: response = serde_json::from_str(&response_text).unwrap();
            db_insert("xsts_web_token", &token.Token).await.unwrap();
            db_insert("xsts_web_token_not_after", &token.NotAfter).await.unwrap();
            db_insert("xsts_web_token_uhs", &token.DisplayClaims.xui[0].uhs).await.unwrap();
            return Ok(xsts_web_token{
                web_token: token.Token,
                uhs: token.DisplayClaims.xui[0].uhs.clone(),
            });
        }
        _ => {
            return Err(anyhow!("xsts_web_token fail to get, status code:{}", response_code));
        }
    }
}

pub async fn get_xsts_stream_token() -> Result<String> {
    {
        // 检查数据库中的xsts_web_token是否存在且未过期
        if let Ok(config) = db_select("xsts_stream_token_not_after").await {
            let expiry:DateTime<Utc> = DateTime::from_str(&config.value).expect("invalid datetime format");
            let now = Utc::now();
            if(now < expiry){
                // 没过期，直接返回
                return Ok(db_select("xsts_stream_token").await.unwrap().value);
            }
        }
    }
    let title_token = get_title_token().await.unwrap();
    let client = Client::new();
    let body = payload{
        Properties: Properties{
            SandboxId: "RETAIL".to_string(),
            DeviceToken: get_sisu_device_token().await.unwrap(),
            TitleToken: title_token,
            UserTokens: vec![get_sisu_user_token().await.unwrap()],
        },
        RelyingParty: "http://gssv.xboxlive.com/".to_string(),
        TokenType: "JWT".to_string(),
    };

    let body = serde_json::to_string(&body).unwrap();
    
    let signature = get_signature("https://xsts.auth.xboxlive.com/xsts/authorize", "", &body);

    let response = client.post("https://xsts.auth.xboxlive.com/xsts/authorize")
        .header("x-xbl-contract-version", "1")
        // .header("Content-Type", "application/json")
        .header("Cache-Control", "no-store, must-revalidate, no-cache")
        .header("Signature", signature)
        .body(body)
        .send().await.unwrap();
    let response_code = response.status().as_u16();
    let response_text = response.text().await.unwrap();

    match response_code {
        200 => {
            let token: response = serde_json::from_str(&response_text).unwrap();
            db_insert("xsts_stream_token", &token.Token).await.unwrap();
            db_insert("xsts_stream_token_not_after", &token.NotAfter).await.unwrap();
            return Ok(token.Token);
        }
        _ => {
            return Err(anyhow!("xsts_stream_token fail to get, status code:{}", response_code));
        }
    }
}